home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Eudora 1.3.1 / source / ctb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-16  |  21.1 KB  |  834 lines  |  [TEXT/MPS ]

  1. #define FILE_NUM 9
  2. /* Copyright (c) 1990-1992 by the University of Illinois Board of Trustees */
  3. /************************************************************************
  4.  * functions for i/o over a pseudo-telnet ctb stream
  5.  * these functions are oriented toward CONVENIENCE, not performance
  6.  ************************************************************************/
  7. #pragma load EUDORA_LOAD
  8. #pragma segment CTBTrans
  9. #include <stdio.h>
  10. static short    CTBErr;
  11.  
  12. /************************************************************************
  13.  * private functions
  14.  ************************************************************************/
  15. Boolean CTBExists(void);
  16. short ConfigureCTB(Boolean makeUser);
  17. short CTBNavigateString(Uptr string);
  18. short MyCMOpen(ConnHandle cn,long timeout);
  19. short MyCMClose(ConnHandle cn);
  20. short MyCMWrite(ConnHandle cn,UPtr buffer,long *size);
  21. short MyCMBreak(ConnHandle cn,long howLong);
  22. short MyCMRead(ConnHandle cn,UPtr buffer,long *size,long timeout);
  23. short GetSecondPass(UPtr pass);
  24. pascal void CTBComplete(ConnHandle cn);
  25. long CTBDataCount(void);
  26. typedef struct
  27. {
  28.     short pending;
  29.     short errCode;
  30.     CMBufferSizes asyncCount;
  31. } AsyncStuff, *AsyncStuffPtr;
  32. Boolean SilentCTB=False;
  33. #define CTBTrouble(err) CTBTR(err,FILE_NUM,__LINE__)
  34. short CTBTR(short err,short file,short line);
  35. #define ESC_AUXUSR 1
  36. #define ESC_AUXUSRERR 2
  37. #define ESC_AUXPW 4
  38. #define ESC_USR 8
  39. #define ESC_PW 16
  40. short EscapeCopy(PStr to,PStr from,PStr expect);
  41.  
  42. /************************************************************************
  43.  * InitCTB - initialize the CommToolbox
  44.  ************************************************************************/
  45. Boolean InitCTB(Boolean makeUser)
  46. {
  47.     static int CTBInitted=0;
  48.     
  49.     CTBInitted = MIN(CTBInitted,4);
  50.     CTBSilenceTrans(False);
  51.     switch (CTBInitted)
  52.     {
  53.         case 0:
  54.             if (!CTBExists())
  55.             {
  56.                 WarnUser(NO_CTB,0);
  57.                 return(False);
  58.             }
  59.             CTBInitted++;
  60.         case 1:
  61.             if (CTBErr = InitCTBUtilities())
  62.             {
  63.                 WarnUser(NO_CTBU,CTBErr);
  64.                 return(False);
  65.             }
  66.             CTBInitted++;
  67.         case 2:
  68.             if (CTBErr = InitCRM())
  69.             {
  70.                 WarnUser(NO_CTBRM,CTBErr);
  71.                 return(False);
  72.             }
  73.             CTBInitted++;
  74.         case 3:
  75.             if (CTBErr = InitCM())
  76.             {
  77.                 WarnUser(NO_CTBCM,CTBErr);
  78.                 return(False);
  79.             }
  80.             CTBInitted++;
  81.         case 4:
  82.             if (CTBErr = ConfigureCTB(makeUser))
  83.                 return(False);
  84.             CTBInitted++;
  85.     }
  86.     return(True);
  87. }
  88.  
  89. /************************************************************************
  90.  * CTBExists - is the CTB installed?
  91.  ************************************************************************/
  92. Boolean CTBExists(void)
  93. {
  94. #define CTBTrap 0x8b
  95. #define UnimplTrap 0x9f
  96.     return(NGetTrapAddress(UnimplTrap,OSTrap)!=NGetTrapAddress(CTBTrap,OSTrap));
  97. }
  98.  
  99. /************************************************************************
  100.  * DialThePhone - create a CTB connection
  101.  ************************************************************************/
  102. short DialThePhone(void)
  103. {
  104.     Str255 scratch;
  105.     
  106.     Progress(NoChange,GetRString(scratch,INIT_CTB));
  107.     if (!InitCTB(False)) return (CTBErr?CTBErr:cmGenericError);
  108.  
  109.     RcvSpot = -1;
  110.     if ((RcvBuffer=NuHandle(GetRLong(RCV_BUFFER_SIZE)))==nil)
  111.     {
  112.         CTBErr=MemError();
  113.         WarnUser(MEM_ERR,CTBErr);
  114.         return(CTBErr);
  115.     }
  116.     Progress(NoChange,GetRString(scratch,MAKE_CONNECT));
  117.     if (CTBErr = MyCMOpen(CnH,60*GetRLong(OPEN_TIMEOUT)))
  118.     {
  119.         CMDispose(CnH);
  120.         CnH = nil;
  121.         return(CTBErr);
  122.     }
  123.     return(CTBNavigateSTRN(NAVIN));
  124. }
  125.     
  126. /************************************************************************
  127.  * CTBConnectTrans - connect to the remote host.    This version uses the CTB.
  128.  ************************************************************************/
  129. int CTBConnectTrans(UPtr serverName, short port)
  130. {
  131.     Str127 scratch;
  132.     
  133. #ifdef DEBUG
  134.     if (BUG12) port += 10000;
  135. #endif
  136.     ComposeRString(scratch,TS_CONNECT_FMT,serverName,(uLong) port);
  137.     Progress(NoBar,scratch);
  138.     CTBSendTrans(1,scratch+1,*scratch);
  139.         
  140.     return(CTBErr);
  141. }
  142.  
  143. /************************************************************************
  144.  * CTBSendTrans - send some text to the remote host.    This version uses the CTB.
  145.  ************************************************************************/
  146. int CTBSendTrans(short count, UPtr text,long size, ...)
  147. {
  148.     long bSize;
  149.     if (size==0) return(noErr);     /* allow vacuous sends */
  150.     CycleBalls();
  151.     
  152.     bSize = size;
  153.     if (CTBErr=MyCMWrite(CnH,text,&bSize))
  154.         return(CTBErr);
  155.     if (--count>0)
  156.     {
  157.         Uptr buffer;
  158.         va_list extra_buffers;
  159.         va_start(extra_buffers,size);
  160.         while (count--)
  161.         {
  162.             CycleBalls();
  163.             buffer = va_arg(extra_buffers,UPtr);
  164.             bSize = va_arg(extra_buffers,int);
  165.             if (CTBSendTrans(1,buffer,bSize)) break;
  166.         }
  167.         va_end(extra_buffers);
  168.     }
  169.     return(CTBErr);
  170. }
  171.  
  172. /************************************************************************
  173.  * GenSendWDS - send a lot of text to the remote host.
  174.  ************************************************************************/
  175. int GenSendWDS(wdsEntry *theWDS)
  176. {
  177.     short err=0;
  178.  
  179.     CycleBalls();
  180.     for (;theWDS->length;theWDS++)
  181.         if (err=SendTrans(1,theWDS->ptr,theWDS->length)) break;
  182.     
  183.     return(err);
  184. }
  185.  
  186. /************************************************************************
  187.  * CTBRecvTrans - get some text from the remote host.  This version uses the CTB.
  188.  ************************************************************************/
  189. int CTBRecvTrans(UPtr line,long *size)
  190. {
  191.     long gotThis;
  192.     Str31 tmStr;
  193.     short factor = 60;
  194.     UPtr spot = line;
  195.     long want = *size;
  196.     
  197.     NumToString(CTBTimeout,tmStr);
  198.     MyCMIdle();
  199.     do
  200.     {
  201.         CTBErr = SpinOn(&CTBHasChars,CTBTimeout*factor);
  202.         if (CTBErr)
  203.             CTBErr = cmTimeOut;
  204.         else
  205.         {
  206.             factor = 10;
  207.             gotThis = CTBDataCount();
  208.             gotThis = MIN(gotThis,want);
  209.             CTBErr=MyCMRead(CnH,line,&gotThis,0);
  210.             if (!CTBErr) {spot += gotThis; want -= gotThis;}
  211.         }
  212.     }
  213.     while (want && spot==line && !SilentCTB && !CommandPeriod &&
  214.                  AlertStr(TIMEOUT_ALRT,Caution,tmStr)==1);
  215.  
  216.     *size = spot - line;
  217.     if (!CTBErr && *size==0) CTBErr = cmTimeOut;
  218.     return(CTBErr);
  219. }
  220.  
  221. /************************************************************************
  222.  *
  223.  ************************************************************************/
  224. void HangUpThePhone(void)
  225. {
  226.     if (CnH)
  227.     {
  228.         Str127 msg;
  229.         (void) CTBNavigateSTRN(NAVOUT);
  230.         Progress(NoChange,GetRString(msg,CTB_CLOSING));
  231.         if (!PrefIsSet(PREF_NO_HANGUP)) (void) MyCMClose(CnH);
  232.     }
  233.     if (CnH)
  234.     {
  235.         CMDispose(CnH);
  236.         CnH = nil;
  237.     }
  238.     if (RcvBuffer) ZapHandle(RcvBuffer);
  239. }
  240.  
  241. /************************************************************************
  242.  * CTBDisTrans - disconnect from the remote host.  This version uses the CTB.
  243.  ************************************************************************/
  244. int CTBDisTrans(void)
  245. {
  246.     return(noErr);
  247. }
  248.  
  249. /************************************************************************
  250.  * CTBDestroyTrans - destory the connection.
  251.  ************************************************************************/
  252. int CTBDestroyTrans(void)
  253. {
  254.     return(noErr);
  255. }
  256.  
  257. /************************************************************************
  258.  * CTBTransError - report our most recent error
  259.  ************************************************************************/
  260. int CTBTransError(void)
  261. {
  262.     return(CTBErr);
  263. }
  264.  
  265. /************************************************************************
  266.  * CTBSilenceTrans - turn off error reports from tcp routines
  267.  ************************************************************************/
  268. void CTBSilenceTrans(Boolean silence)
  269. {
  270.     SilentCTB = silence;
  271. }
  272.  
  273. /************************************************************************
  274.  * ConfigureCTB - configure the communications toolbox
  275.  ************************************************************************/
  276. short ConfigureCTB(Boolean makeUser)
  277. {
  278.     Str63 toolName;
  279.     short procID;
  280.     CMBufferSizes bs;
  281.     Point pt;
  282.     short result;
  283.     Handle cfigH;
  284.     Boolean needConfig = True;
  285.     
  286.     CTBErr = 0;
  287.     
  288.     /*
  289.      * find the tool to use
  290.      */
  291.     if (!*GetRStr(toolName,CTB_TOOL_STR)) return(1);
  292.     
  293.     if ((procID=CMGetProcID(toolName))<0)
  294.     {
  295.         CRMGetIndToolName(classCM,1,toolName);
  296.         if (!*toolName)
  297.             return(WarnUser(NO_CTB_TOOLS,1));
  298.         else if ((procID=CMGetProcID(toolName))<0)
  299.             return(WarnUser(COULDNT_GET_TOOL,1));
  300.     }
  301.     
  302.     /*
  303.      * create a connection record
  304.      */
  305.     WriteZero(bs,sizeof(bs));
  306.     if (!(CnH = CMNew(procID,
  307.             cmNoMenus|(PrefIsSet(PREF_AUTO_DISMISS)?cmQuiet:0),bs,nil,nil)))
  308.     {
  309.         WarnUser(MEM_ERR,MemError());
  310.         return(1);
  311.     }
  312.     
  313.     /*
  314.      * try to load the old configuration
  315.      */
  316.     if (cfigH = GetNamedResource(CTB_CFIG_TYPE,toolName))
  317.     {
  318.         if (GetPtrSize((*CnH)->config)==GetHandleSize(cfigH))
  319.         {
  320.             BlockMove(*cfigH,(*CnH)->config,GetPtrSize((*CnH)->config));
  321.             BlockMove(*cfigH,(*CnH)->oldConfig,GetPtrSize((*CnH)->config));
  322.             needConfig = CMValidate(CnH);
  323.         }
  324.         ReleaseResource(cfigH);
  325.     }
  326.     
  327.     /*
  328.      * let the user have a look at things
  329.      */
  330.     if (makeUser || needConfig)
  331.     {
  332.         pt.h = 10; pt.v = GetMBarHeight()+10;
  333.         switch (result = CMChoose(&CnH,pt,nil))
  334.         {
  335.             case chooseDisaster:
  336.             case chooseFailed:
  337.             case chooseAborted:
  338.                 CTBErr = result;
  339.                 break;
  340.             case chooseOKMajor:
  341.             case chooseOKMinor:
  342.                 /* save the name string */
  343.                 CMGetToolName((*CnH)->procID,toolName);
  344.                 BlockMove((*CnH)->config,(*CnH)->oldConfig,GetPtrSize((*CnH)->config));
  345.                 if (CTBErr = SettingsPtr('STR ',nil,CTB_TOOL_STR,toolName,*toolName+1))
  346.                     WarnUser(WRITE_SETTINGS,CTBErr);
  347.                 else if (CTBErr = SettingsPtr(CTB_CFIG_TYPE,toolName,CTB_CFIG_ID,
  348.                                                                         (*CnH)->config,GetPtrSize((*CnH)->config)))
  349.                     WarnUser(WRITE_SETTINGS,CTBErr);
  350.                 break;
  351.         }
  352.     }
  353.     
  354.     /*
  355.      * just configuring?
  356.      */
  357.     if (CnH)
  358.         if (makeUser) {CMDispose(CnH); CnH = nil;}
  359.     
  360.     return(CTBErr);
  361. }
  362.  
  363. /************************************************************************
  364.  * CTBNavigateSTRN - navigate a serial connection by means of an STRN resource
  365.  ************************************************************************/
  366. short CTBNavigateSTRN(short id)
  367. {
  368.     short count,n;
  369.     Str63 name;
  370.     Uhandle strnH;
  371.     Str255 string;
  372.     ResType theType;
  373.     Boolean oldSilence = SilentCTB;
  374.     short err=noErr;
  375.     
  376.     GetRString(name,id);
  377.     CMGetToolName((*CnH)->procID,string);
  378.     PCatC(string,' ');
  379.     PCat(string,name);
  380.     strnH = GetNamedResource('STR#',string);
  381.     if (!strnH)
  382.         strnH = GetNamedResource('STR#',name);
  383.     if (!strnH)
  384.         strnH = GetResource('STR#',id==NAVIN ? CTB_NAV_IN_STRN :
  385.             (id==NAVMID ? CTB_NAV_MID_STRN : CTB_NAV_OUT_STRN));
  386.     
  387.     if (strnH)
  388.     {
  389.         CTBTimeout = GetRLong(SHORT_TIMEOUT);
  390.         count = (*strnH)[0]*256 + (*strnH)[1];
  391.         GetResInfo(strnH,&id,&theType,name);
  392.         ReleaseResource(strnH);
  393.         ComposeLogR(LOG_NAV,nil,NAV_BEGIN,name,id,count);
  394.         
  395.         CTBSilenceTrans(True);
  396.         for (n=1; n<=count; n++)
  397.         {
  398.             GetIndString(string,id,n);
  399.             if (err=CTBNavigateString(string)) break;
  400.         }
  401.         CTBSilenceTrans(oldSilence);
  402.         CTBTimeout = GetRLong(RECV_TIMEOUT);
  403.         if (err!=cmTimeOut) CTBTrouble(err);
  404.     }
  405.         
  406.     return(err==cmTimeOut ? noErr : err);
  407. }
  408.  
  409. /************************************************************************
  410.  * CTBNavigateString - navigate a serial connection by a string
  411.  ************************************************************************/
  412. short CTBNavigateString(Uptr string)
  413. {
  414.     Str255 data, scratch, expect;
  415.     long bSize;
  416.     long tics;
  417.     UPtr exSpot,dSpot;
  418.     Boolean found=False,brk=False,wait=False;
  419.     short escFlags;
  420.     
  421.     escFlags = EscapeCopy(data,string,expect);
  422.     for (exSpot=expect+*expect;exSpot>expect;exSpot--) *expect &= 0x7f;    /* strip parity */
  423.     
  424.     if (CommandPeriod) return(userCancelled);
  425.     if (escFlags & ESC_AUXUSRERR)
  426.     {
  427.         WarnUser(NO_AUXUSR,0);
  428.         return(userCancelled);
  429.     }
  430.  
  431.     if (*data && data[1]==bulletChar)
  432.     {
  433.         Progress(NoChange,GetRString(scratch,SECRET));
  434.         BlockMove(data+2,data+1,*data-1);
  435.         --*data;
  436.     }
  437.     else if (*data && ((brk=data[1]==betaChar) || (wait=data[1]==deltaChar)))
  438.     {
  439.         BlockMove(data+2,data+1,*data);
  440.         --*data;
  441.         tics = atoi(data+1);
  442.         if (wait) tics *= 60;
  443.         Progress(NoChange,ComposeRString(scratch,brk?BREAKING:WAITING,tics));
  444.     }
  445.     else
  446.     {
  447.         Progress(NoChange,data);
  448.     }
  449.  
  450.     CarefulLog(LOG_NAV,LOG_SENT,data+1,*data);
  451.     if (brk)
  452.     {
  453.         if (CTBErr=MyCMBreak(CnH,tics)) return(CTBErr);
  454.     }
  455.     else if (wait)
  456.       for (tics+=TickCount();TickCount()<tics;) GiveTime();
  457.     else if (CTBErr=CTBSendTrans(1,data+1,*data)) return(CTBErr);
  458.     if (*expect)
  459.     {
  460.         CarefulLog(LOG_NAV,LOG_EXPECT,expect+1,*expect);
  461.         tics = TickCount()+GetRLong(RECV_TIMEOUT)*60;
  462.         exSpot = expect+1;
  463.     }
  464.     do
  465.     {
  466.         bSize = sizeof(data)-1;
  467.         CTBErr = RecvLine(data+1,&bSize);
  468.         if (bSize)
  469.         {
  470.             data[0] = bSize;
  471.             Progress(NoChange,data);
  472.             CarefulLog(LOG_NAV,LOG_GOT,data+1,*data);
  473.             if (*expect)
  474.             {
  475.                 for(dSpot=data+1;dSpot<=data+*data;dSpot++)
  476.                     if ((*dSpot&0x7f)==*exSpot)
  477.                     {
  478.                         if (++exSpot>expect+*expect)
  479.                         {
  480.                             ComposeLogR(LOG_NAV,nil,LOG_FOUND);
  481.                             found = True;
  482.                             break;
  483.                         }
  484.                     }
  485.                     else
  486.                         exSpot = expect+1;
  487.             }
  488.         }
  489.         if (*expect && TickCount()>tics)
  490.         {
  491.             GetRString(scratch,RECV_TIMEOUT);
  492.             CTBSilenceTrans(False);
  493.             if (AlertStr(TIMEOUT_ALRT,Caution,scratch)==1)
  494.                 tics = TickCount()+60*GetRLong(RECV_TIMEOUT);
  495.             else
  496.             {
  497.                 ComposeLogR(LOG_NAV,nil,LOG_NOTFOUND);
  498.                 CTBErr = userCancelled;
  499.             }
  500.             CTBSilenceTrans(True);
  501.         }
  502.     }
  503.     while (!CommandPeriod && (!CTBErr || CTBErr==cmTimeOut&&*expect) && !found);
  504.     if (CTBErr==cmTimeOut) CTBErr = 0;
  505.     if (*expect && !found)
  506.     {
  507.         CTBErr = userCancelled;
  508.         InvalidatePasswords(0==(escFlags&ESC_PW),0==(escFlags&ESC_AUXPW));
  509.     }
  510.     return(CTBErr);
  511. }
  512.  
  513. /************************************************************************
  514.  * MyCMClose - call CMClose
  515.  ************************************************************************/
  516. short MyCMClose(ConnHandle cn)
  517. {
  518.     AsyncStuff stuff;
  519.     short err;                        /* real error */
  520.  
  521.     (*cn)->refCon = (long) &stuff;                /* store address */
  522.     stuff.pending = 1;
  523.     if (PrefIsSet(PREF_SYNCH_CTB))
  524.         err=CMClose(cn,False,nil,-1,True);
  525.     else
  526.     {
  527.         (void) CMIOKill(cn,cmDataIn);
  528.         (void) CMIOKill(cn,cmDataOut);
  529.         if (!(err=CMClose(cn,True,CTBComplete,-1,True)))
  530.             err = SpinOn(&stuff.pending,0) || stuff.errCode;
  531.             
  532.     }
  533.     CTBTrouble(err);
  534.     return (err);                 /* error? */
  535. }
  536.  
  537. /************************************************************************
  538.  * MyCMOpen - call CMOpen
  539.  ************************************************************************/
  540. short MyCMOpen(ConnHandle cn,long timeout)
  541. {
  542.     AsyncStuff stuff;                                         
  543.     short err;                        /* real error */
  544.     
  545.     (*cn)->refCon = (long) &stuff;                /* store address */
  546.     stuff.pending = 1;
  547.     if (PrefIsSet(PREF_SYNCH_CTB))
  548.         err=CMOpen(cn,False,CTBComplete,timeout);
  549.     else
  550.     {
  551.         if (!(err=CMOpen(cn,True,CTBComplete,timeout)))
  552.         {
  553.             err = SpinOn(&stuff.pending,0) || stuff.errCode;
  554.             if (err==userCancelled)
  555.                 (void) CMAbort(CnH);
  556.         }
  557.     }
  558.  
  559.     CTBTrouble(err);
  560.     return (err);
  561. }
  562.  
  563. /************************************************************************
  564.  * MyCMRead - call CMRead
  565.  ************************************************************************/
  566. short MyCMRead(ConnHandle cn,UPtr buffer,long *size,long timeout)
  567. {
  568.     AsyncStuff stuff;
  569.     short err;                        /* real error */
  570.     CMFlags junk;
  571.     
  572.     (*cn)->refCon = (long)&stuff;
  573.     stuff.pending = 1;
  574.     if (!(err=CMRead(cn,buffer,size,cmData,True,CTBComplete,timeout,&junk)))
  575.     {
  576.         err = SpinOn(&stuff.pending,0) || stuff.errCode;
  577.         if (err==userCancelled)
  578.             CMIOKill(cn,cmDataIn);
  579.     }
  580.  
  581.     if (!err || err==cmTimeOut)
  582.     {
  583.         *size = stuff.asyncCount[cmDataIn];
  584.         if (*size) err = noErr;
  585.         else err = cmTimeOut;
  586.     }
  587.     else
  588.         *size = 0;
  589.     if (*size && LogLevel&LOG_TRANS) CarefulLog(LOG_TRANS,LOG_GOT,buffer,*size);
  590.     if (err!=cmTimeOut) CTBTrouble(err);
  591.     return(err);
  592. }
  593.  
  594. /************************************************************************
  595.  * MyCMWrite - call CMWrite
  596.  ************************************************************************/
  597. short MyCMWrite(ConnHandle cn,UPtr buffer,long *size)
  598. {
  599.     AsyncStuff stuff;
  600.     short err;                        /* real error */
  601.     (*cn)->refCon = (long)&stuff;
  602.     stuff.pending = 1;
  603.     if (!DontTranslate && TransOut)
  604.         {Uptr cp; for(cp=buffer;cp<buffer+*size;cp++) *cp = TransOut[*cp];}
  605.     if (LogLevel&LOG_TRANS) CarefulLog(LOG_TRANS,LOG_SENT,buffer,*size);
  606.     if (!(err=CMWrite(cn,buffer,size,cmData,True,CTBComplete,-1,0)))
  607.     {
  608.         err = SpinOn(&stuff.pending,0) || stuff.errCode;
  609.         if (err==userCancelled)
  610.             CMIOKill(cn,cmDataOut);
  611.     }
  612.  
  613.     if (!err)
  614.         *size = stuff.asyncCount[cmDataOut];
  615.     else
  616.         *size = 0;
  617.  
  618.     CTBTrouble(err);
  619.     return(err);
  620. }
  621.  
  622. /************************************************************************
  623.  * MyCMBreak - call CMBreak
  624.  ************************************************************************/
  625. short MyCMBreak(ConnHandle cn,long howLong)
  626. {
  627.     AsyncStuff stuff;
  628.     short err;                        /* real error */
  629.     (*cn)->refCon = (long)&stuff;
  630.     stuff.pending = 1;
  631.     CMBreak(cn,howLong,True,CTBComplete);
  632.     
  633.     err = SpinOn(&stuff.pending,0) || stuff.errCode;
  634.     if (err==userCancelled)
  635.         CMIOKill(cn,cmDataOut);
  636.  
  637.     CTBTrouble(err);
  638.     return(err);
  639. }
  640.  
  641. /************************************************************************
  642.  * CTBTR - report a CTB error
  643.  ************************************************************************/
  644. short CTBTR(short err,short file,short line)
  645. {
  646.     Uhandle strnH;
  647.     
  648.     if (!SilentCTB &&!CommandPeriod && err && err!=userCancelled)
  649.     {
  650.         strnH = GetResource('STR#',CTB_ERR_STRN);
  651.         if (strnH)
  652.         {
  653.             Str127 errString,debugStr,message;
  654.             if (err+2 > 0 && err+2 <= (*strnH)[0]*256 + (*strnH)[1])
  655.                 GetRString(errString,CTB_ERR_STRN+err+2);
  656.             else
  657.                 NumToString(err,errString);
  658.             ReleaseResource(strnH);
  659.             GetRString(message,CTB_PROBLEM);
  660.             ComposeRString(debugStr,FILE_LINE_FMT,file,line);
  661.             MyParamText(message,errString,"",debugStr);
  662.             (void) ReallyDoAnAlert(OK_ALRT,Caution);
  663.             CTBSilenceTrans(True);
  664.         }
  665.     }
  666.     return(err);
  667. }
  668.  
  669. /************************************************************************
  670.  * CTBWhoAmI - return the mac's ctb name
  671.  ************************************************************************/
  672. UPtr CTBWhoAmI(Uptr who)
  673. {
  674.     return(GetRString(who,CTB_ME));
  675. }
  676.  
  677. /************************************************************************
  678.  * MyCMIdle - do the things I should do at CMIdle time
  679.  ************************************************************************/
  680. void MyCMIdle(void)
  681. {
  682.     CMIdle(CnH);
  683.     CTBHasChars = CTBDataCount() ? noErr : inProgress;
  684. }
  685.  
  686. /************************************************************************
  687.  * CTBDataCount - how much data do we have?
  688.  ************************************************************************/
  689. long CTBDataCount(void)
  690. {
  691.     CMStatFlags flags;
  692.     CMBufferSizes sizes;
  693.     
  694.     CMStatus(CnH,sizes,&flags);
  695.     return(flags&cmStatusDataAvail ? sizes[cmDataIn] : 0);
  696. }
  697.  
  698. /************************************************************************
  699.  * GetSecondPass - get the user's secondary password
  700.  ************************************************************************/
  701. short GetSecondPass(UPtr pass)
  702. {
  703.     Str31 save;
  704.     short err;
  705.     Str31 dialup;
  706.     
  707.     if (!*SecondPass)
  708.     {
  709.         PCopy(save,Password);
  710.         *Password = 0;
  711.         GetRString(dialup,DIALUP);
  712.         if (!(err=GetPassword(dialup,pass,32,ENTER)))
  713.         {
  714.             PCopy(SecondPass,pass);
  715.             if (PrefIsSet(PREF_SAVE_PASSWORD) && *SecondPass)
  716.             {
  717.                 ChangeStrn(PREF_STRN,PREF_AUXPW,Password);
  718.                 UpdateResFile(SettingsRefN);
  719.             }
  720.         }
  721.         PCopy(Password,save);
  722.         return(err);
  723.     }
  724.     else
  725.     {
  726.         PCopy(pass,SecondPass);
  727.         return(noErr);
  728.     }
  729. }
  730.  
  731. #pragma segment Transport
  732. /************************************************************************
  733.  * EscapeCopy - copy a string, expanding escapes
  734.  ************************************************************************/
  735. short EscapeCopy(PStr to,PStr from,PStr expect)
  736. {
  737.     UPtr end = from+*from;
  738.     UPtr spot = to+1;
  739.     Boolean esc;
  740.     Str127 scratch1, scratch2;
  741.     short returnVal=0;
  742.     
  743.     *expect = 0;
  744.     from++;
  745.     for (esc=false; from<=end; from++)
  746.     {
  747.         if (esc)
  748.         {
  749.             esc = False;
  750.             switch (*from)
  751.             {
  752.                 case 'U':
  753.                     GetPref(scratch1,PREF_AUXUSR);
  754.                     BlockMove(scratch1+1,spot,*scratch1);
  755.                     spot += *scratch1;
  756.                     returnVal |= ESC_AUXUSR;
  757.                     if (!*scratch1) returnVal |= ESC_AUXUSRERR;
  758.                     break;
  759.                 case 'P':
  760.                     if (GetSecondPass(SecondPass))
  761.                     {
  762.                         CommandPeriod = True;
  763.                         break;
  764.                     }
  765.                     BlockMove(SecondPass+1,spot,*SecondPass);
  766.                     spot += *SecondPass;
  767.                     returnVal |= ESC_AUXPW;
  768.                     break;
  769.                 case 'u':
  770.                     GetPOPInfo(scratch1,scratch2);
  771.                     BlockMove(scratch1+1,spot,*scratch1);
  772.                     spot += *scratch1;
  773.                     returnVal |= ESC_USR;
  774.                     break;
  775.                 case 'h':
  776.                     GetPOPInfo(scratch1,scratch2);
  777.                     BlockMove(scratch2+1,spot,*scratch2);
  778.                     spot += *scratch2;
  779.                     break;
  780.                 case 's':
  781.                     GetSMTPInfo(scratch1);
  782.                     BlockMove(scratch1+1,spot,*scratch1);
  783.                     spot += *scratch1;
  784.                     break;
  785.                 case 'e':                        /* switch to 'expect' string */
  786.                     *to = spot-to-1;
  787.                     to[*to+1] = 0;
  788.                     to = expect;
  789.                     spot=to+1;
  790.                     break;
  791. #ifndef KERBEROS
  792.                 case 'p':
  793.                     BlockMove(Password+1,spot,*Password);
  794.                     spot += *Password;
  795.                     returnVal |= ESC_PW;
  796.                     break;
  797. #endif
  798.                 case 'n': *spot++ = '\r'; break;
  799.                 case 'r': *spot++ = '\n'; break;
  800.                 case 'b': *spot++ = bulletChar; break;
  801.                 case 'B': *spot++ = betaChar; break;
  802.                 case 'D': *spot++ = deltaChar; break;
  803.                 default: *spot++ = *from; break;
  804.             }
  805.         }
  806.         else
  807.         {
  808.             esc = *from=='\\';
  809.             if (!esc) *spot++ = *from;
  810.         }
  811.     }
  812.     *to = spot-to-1;
  813.     to[*to+1] = 0;    /* null terminate, just for fun */
  814.     return(returnVal);
  815. }
  816.  
  817. #pragma segment Main
  818.  
  819. /************************************************************************
  820.  * CTBComplete - completion routine
  821.  ************************************************************************/
  822. pascal void CTBComplete(ConnHandle cn)
  823. {
  824.     AsyncStuffPtr stuffP = (AsyncStuffPtr)(*cn)->refCon;
  825.     uLong *fp, *tp, *ep;
  826.     
  827.     stuffP->errCode = (*cn)->errCode;
  828.     fp=(*cn)->asyncCount;
  829.     tp=stuffP->asyncCount;
  830.     ep=tp+sizeof(CMBufferSizes)/sizeof(uLong);
  831.     while (tp<ep) *tp++ = *fp++;
  832.     stuffP->pending = 0;
  833. }
  834.